package com.xyht.sca_s.student_manage_system.modules.clockIn.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.ApiModelUtil;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.clockIn.entity.*;
import com.xyht.sca_s.student_manage_system.modules.clockIn.entity.req.SmsClockInApplyAddReq;
import com.xyht.sca_s.student_manage_system.modules.clockIn.entity.req.SmsClockInApplyAllowReq;
import com.xyht.sca_s.student_manage_system.modules.clockIn.entity.req.SmsClockInApplyHistoryReq;
import com.xyht.sca_s.student_manage_system.modules.clockIn.entity.req.SmsClockInHistoryReq;
import com.xyht.sca_s.student_manage_system.modules.clockIn.entity.resp.*;
import com.xyht.sca_s.student_manage_system.modules.clockIn.mapper.*;
import com.xyht.sca_s.student_manage_system.modules.clockIn.service.SmsClockInApplyService;
import com.xyht.sca_s.student_manage_system.modules.meeting.entity.SmsMeetingRoomProcessDetail;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.AppTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.RangeTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.TipsTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.util.NewTipsUtil;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsRole;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsUser;
import com.xyht.sca_s.student_manage_system.modules.user.mapper.SmsRoleMapper;
import com.xyht.sca_s.student_manage_system.modules.user.mapper.SmsUserMapper;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.clockIn.constant.ClockInApplyStatusConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.clockIn.constant.ClockInExamineTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.clockIn.constant.ClockInObjectTypeConstant.CLOCK_IN_OBJECT_TYPE_PERSON;
import static com.xyht.sca_s.student_manage_system.modules.clockIn.constant.ClockInObjectTypeConstant.CLOCK_IN_OBJECT_TYPE_ROLE;
import static com.xyht.sca_s.student_manage_system.modules.clockIn.constant.ClockInStateConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.clockIn.constant.ClockInTypeConstant.CLOCK_IN_TYPE_START;
import static com.xyht.sca_s.student_manage_system.modules.clockIn.constant.IsExportProcessConstant.EXPORT_PROCESS_TRUE;
import static com.xyht.sca_s.student_manage_system.modules.student.constant.StudentInfoCommonConstant.PER_SHEET_NUM;

/**
 * <p>
 * 补卡申请表 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-08-03
 */
@Service
public class SmsClockInApplyServiceImpl extends ServiceImpl<SmsClockInApplyMapper, SmsClockInApply> implements SmsClockInApplyService {

    @Resource
    private SmsClockInMapper clockInMapper;
    @Resource
    private SmsClockInClassesSettingMapper classesSettingMapper;
    @Resource
    private SmsClockInGroupSettingMapper groupSettingMapper;
    @Resource
    private SmsClockInApplyMapper clockInApplyMapper;
    @Resource
    private SmsClockInApplyDetailMapper clockInApplyDetailMapper;
    @Resource
    private NewTipsUtil newTipsUtil;
    @Resource
    private CacheUtil cacheUtil;
    @Resource
    private SmsClockInApplyMpjMapper smsClockInApplyMpjMapper;
    @Resource
    private SmsRoleMapper smsRoleMapper;
    @Resource
    private SmsUserMapper smsUserMapper;
    @Resource
    private ApiModelUtil apiModelUtil;

    @Override
    public ResponseResult getAbnormalRecords(String userId, String abnormalDateStr) {

        List<SmsAbnormalRecordsResp> abnormalRecordsList = new ArrayList<>();
        if(!isNullOrEmpty(abnormalDateStr)) {
            Date abnormalDate = TimeUtil.StringtoDate(abnormalDateStr);
            if(isNullOrEmpty(abnormalDate)){
               return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
            }
            abnormalRecordsList = clockInMapper.selectList(new LambdaQueryWrapper<SmsClockIn>()
                    .eq(SmsClockIn::getClockInDate, abnormalDate)
                    .eq(SmsClockIn::getUserId, userId))
                    .stream()
                    .map(clockIn ->{
                        SmsAbnormalRecordsResp abnormalRecordsResp = new SmsAbnormalRecordsResp();
                        SmsClockInGroupSetting clockInGroupSetting = groupSettingMapper.selectById(clockIn.getClockInGroupId());
                        if(!isNullOrEmpty(clockInGroupSetting)){
                            Boolean isAllowClockIn = clockInGroupSetting.getIsAllowClockIn();
                            if(isAllowClockIn){
                                List<Integer> repairType = JSONObject.parseArray(clockInGroupSetting.getRepairType(), Integer.class);
                                if(repairType.contains(clockIn.getClockInState())){
                                    abnormalRecordsResp.setClockInId(clockIn.getId());
                                    abnormalRecordsResp.setClockInType(clockIn.getClockInType());//打卡类型
                                    abnormalRecordsResp.setClockInState(clockIn.getClockInState());//打卡状态
                                    SmsClockInClassesSetting classesSetting = classesSettingMapper.selectById(clockIn.getClassesId());
                                    if(classesSetting != null) {
                                        abnormalRecordsResp.setShouldStartHours(TimeUtil.TimeFormatSting(classesSetting.getStartHours()));//上班应打卡时间
                                        abnormalRecordsResp.setShouldEndHours(TimeUtil.TimeFormatSting(classesSetting.getEndHours()));//下班应打卡时间
                                    }
                                }
                            }
                        }
                        return abnormalRecordsResp;
                    })
                    .collect(Collectors.toList());
        }
        return CommonResult.success(abnormalRecordsList);
    }

    @Override
    public ResponseResult getClockInProcess() {
        SmsClockInGroupSetting groupSetting = groupSettingMapper.selectList(new LambdaQueryWrapper<SmsClockInGroupSetting>()
                .orderByDesc(SmsClockInGroupSetting::getUpdateObjectIdTime)).get(0);
        SmsClockInGroupSettingProcessResp processResp = new SmsClockInGroupSettingProcessResp();
        processResp.setId(groupSetting.getId());
        processResp.setAllowUserType(groupSetting.getAllowUserType());
        List<String> list = JSONObject.parseArray(groupSetting.getAllowUserId(), String.class);
        List<SmsClockInUserResp> allowUserInfoList = new ArrayList<>();
        List<String> objectNameList = new ArrayList<>();
        for (String allowUserId : list) {
            SmsClockInUserResp clockInUserResp = new SmsClockInUserResp();
            if (groupSetting.getAllowUserType() == CLOCK_IN_OBJECT_TYPE_PERSON) {
                SmsUser allowUserInfo = cacheUtil.getUserInfo(allowUserId);
                if (allowUserInfo != null) {
                    BeanUtils.copyProperties(allowUserInfo, clockInUserResp);
                }
                allowUserInfoList.add(clockInUserResp);
            } else if (groupSetting.getAllowUserType() == CLOCK_IN_OBJECT_TYPE_ROLE) {
                SmsRole smsRole = smsRoleMapper.selectById(allowUserId);
                if (smsRole != null) {
                    objectNameList.add(smsRole.getRoleName());
                }
            }
        }
        processResp.setAllowUserInfoList(allowUserInfoList);
        processResp.setObjectNameList(objectNameList);
        return CommonResult.success(processResp);
    }

    @Override
    @Transactional
    public ResponseResult addRepairClockInApply(String userId, SmsClockInApplyAddReq applyAddReq) {
        if(isNullOrEmpty(applyAddReq.getClockInId()) || isNullOrEmpty(applyAddReq.getRepairTime())
                || isNullOrEmpty(applyAddReq.getAbnormalDate()) || isNullOrEmpty(applyAddReq.getRepairReason())){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsClockIn clockIn = clockInMapper.selectById(applyAddReq.getClockInId());
        if(clockIn == null){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_NOT_EXIST);
        }

        //先校验是否存在补卡申请中
        List<SmsClockInApply> waitAllowClockInApplies = clockInApplyMapper.selectList(new LambdaQueryWrapper<SmsClockInApply>()
                .eq(SmsClockInApply::getApplyUserId, userId)
                .eq(SmsClockInApply::getAllowStatus, CLOCK_IN_APPLY_STATUS_WAIT_ALLOW));
        if(waitAllowClockInApplies != null && waitAllowClockInApplies.size() > 0){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_APPLY_EXIST);
        }
        //考勤组id
        String clockInGroupId = clockIn.getClockInGroupId();
        SmsClockInGroupSetting groupSetting = groupSettingMapper.selectById(clockInGroupId);
        if(groupSetting == null){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_GROUP_NOT_EXIST);
        }
        //校验是否允许补卡
        if(!groupSetting.getIsAllowClockIn()){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN__NOT_ALLOW_REPAIR);
        }
        //校验补卡类型
        List<Integer> repairTypeList = JSONObject.parseArray(groupSetting.getRepairType(), Integer.class);
        if (!repairTypeList.contains(clockIn.getClockInState())) {
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN__NOT_ALLOW_REPAIR_TYPE);
        }
        Date abnormalDate = TimeUtil.StringtoDate(applyAddReq.getAbnormalDate());
        Date shouldRepairTime = TimeUtil.TimeFormat(applyAddReq.getRepairTime());
        //校验是否限制补卡时间
        if(groupSetting.getIsRepairTime()){
            float calculateTimeGapDay = TimeUtil.calculateTimeGapDay(abnormalDate, new Date());
            float repairTime = groupSetting.getRepairTime();
            //超过考勤设置的补卡时间范围内
            if(calculateTimeGapDay > repairTime){
                return CommonResult.failed(CommonCodeEnum.CLOCK_IN__REPAIR_TIME_OVER);
            }
        }
        //校验补卡次数
        Integer repairClockInCount = clockInApplyMapper.selectCount(new LambdaQueryWrapper<SmsClockInApply>()
                .eq(SmsClockInApply::getApplyUserId, userId)
                .eq(SmsClockInApply::getAllowStatus, CLOCK_IN_APPLY_STATUS_PASS));
        if(groupSetting.getIsRepairTimes()){
            Integer repairTimes = groupSetting.getRepairTimes();
            if(repairClockInCount > repairTimes){
                return CommonResult.failed(CommonCodeEnum.CLOCK_IN__REPAIR_TIMES_OVER);
            }
        }

        //创建申请表
        SmsClockInApply addClockInApply = new SmsClockInApply();
        BeanUtils.copyProperties(applyAddReq,addClockInApply);
        addClockInApply.setAbnormalDate(abnormalDate);
        addClockInApply.setRepairTime(shouldRepairTime);
        addClockInApply.setApplyUserId(userId);
        addClockInApply.setAllowStatus(CLOCK_IN_APPLY_STATUS_WAIT_ALLOW);//待审批
        clockInApplyMapper.insert(addClockInApply);

        String applyId = addClockInApply.getId();
        RangeTypeEnum rangeTypeEnum;
        if (groupSetting.getIsAllow()) {
            List<String> rangeList = new ArrayList<>();
            rangeList = JSONObject.parseArray(groupSetting.getAllowUserId(), String.class);
            for (String allowUserId : rangeList) {
                //创建审批节点表
                SmsClockInApplyDetail addClockInApplyDetail = new SmsClockInApplyDetail();
                addClockInApplyDetail.setExamineId(applyId);
                addClockInApplyDetail.setProcessObjectType(groupSetting.getAllowUserType());//审批人类型
                addClockInApplyDetail.setProcessObjectId(allowUserId);//审批人
                addClockInApplyDetail.setDetailAllowStatus(CLOCK_IN_APPLY_STATUS_WAIT_ALLOW);//待审批
                clockInApplyDetailMapper.insert(addClockInApplyDetail);
                //消息提醒
                if (groupSetting.getAllowUserType() == CLOCK_IN_OBJECT_TYPE_PERSON) {
                    rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
                } else {
                    rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_ROLE;
                }
                newTipsUtil.addNewTips(TipsTypeEnum.TIPS_TYPE_ENUM_ALLOW,
                        userId,
                        rangeTypeEnum,
                        rangeList,
                        AppTypeEnum.APP_TYPE_ENUM_CLOCK_IN,
                        applyId,
                        addClockInApplyDetail.getId());
            }

        //不需要审批 直接通过
        } else {
            //修改申请表
            SmsClockInApply updateClockInApply = new SmsClockInApply();
            updateClockInApply.setId(applyId);
            updateClockInApply.setProcessEndTime(new Date());
            updateClockInApply.setAllowStatus(CLOCK_IN_APPLY_STATUS_PASS);
            clockInApplyMapper.updateById(updateClockInApply);
            //修改打卡表
            SmsClockIn updateClockIn = new SmsClockIn();
            updateClockIn.setId(clockIn.getId());
            updateClockIn.setClockInDate(abnormalDate);//补卡日期
            updateClockIn.setClockInTime(shouldRepairTime);//补卡时间
            updateClockIn.setClockInState(CLOCK_IN_STATE_NORMAL);//打卡状态 正常
            clockInMapper.updateById(updateClockIn);
            //消息提醒
            newTipsUtil.allowFinishTips(applyId, userId, true);
        }
        return CommonResult.success();
    }

    @Override
    public ResponseResult getRepairClockInApplyList(String userId, Integer applyType, Integer pageSize, Integer pageNum,String search_str) {
        if(isNullOrEmpty(applyType)){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        //构造回传数据
        List<SmsClockInApplyResp> respList = new ArrayList<>();
        int total = 0;

        //根据applyType进行相关处理
        if (applyType == CLOCK_IN_EXAMINE_TYPE_APPLY) {//已发起
            Page<SmsClockInApply> page = new Page<>(pageNum, pageSize);
            LambdaQueryWrapper<SmsClockInApply> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SmsClockInApply::getApplyUserId, userId)
                    .orderByDesc(SmsClockInApply::getCreateTime);
            if(!isNullOrEmpty(search_str)){
                List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                        .lambda()
                        .like(SmsUser::getRealName, search_str))
                        .stream()
                        .map(SmsUser::getId).collect(Collectors.toList());
                queryWrapper.and(i -> {
                    i.like(SmsClockInApply::getRepairReason, search_str);
                    if (userIds.size() > 0) {
                        i.or().in(SmsClockInApply::getApplyUserId,search_str);
                    }
                });
            }
            clockInApplyMapper.selectPage(page, queryWrapper);
            respList = page.getRecords().stream().map(apply -> {
                SmsClockInApplyResp applyResp = new SmsClockInApplyResp();
                BeanUtils.copyProperties(apply, applyResp);
                //时间转换
                applyResp.setAbnormalDate(TimeUtil.DateSimpleformat(apply.getAbnormalDate()));
                applyResp.setRepairTime(TimeUtil.TimeFormatSting(apply.getRepairTime()));
                applyResp.setApplyId(apply.getId());
                //获取当前用户信息
                SmsUser smsUser = cacheUtil.getUserInfo(apply.getApplyUserId());
                SmsClockInUserResp userResp = new SmsClockInUserResp();
                if (smsUser != null) {
                    BeanUtils.copyProperties(smsUser, userResp);
                }
                applyResp.setApplyUserInfo(userResp);
                return applyResp;
            }).collect(Collectors.toList());
            total = (int) page.getTotal();
        } else if (applyType == CLOCK_IN_EXAMINE_TYPE_ALLOWED) {//已办
            Page<SmsClockInApplyMpjResp> page = new Page<>(pageNum, pageSize);
            MPJLambdaWrapper<SmsClockInApplyDetail> mpjLambdaWrapper = new MPJLambdaWrapper<>();
            mpjLambdaWrapper.selectAll(SmsClockInApplyDetail.class).selectAll(SmsClockInApply.class)
                    .selectAs(SmsClockInApply::getCreateTime, "applyCreateTime")
                    .selectAs(SmsClockInApplyDetail::getId, "detailId")
                    .leftJoin(SmsClockInApply.class, SmsClockInApply::getId, SmsClockInApplyDetail::getExamineId)
                    .eq(SmsClockInApplyDetail::getDetailAllowUserId, userId)
                    .orderByDesc(SmsClockInApplyDetail::getDetailAllowTime);
            mpjLambdaWrapper.and(wrapper -> {
                wrapper.eq(SmsClockInApplyDetail::getDetailAllowStatus, CLOCK_IN_APPLY_STATUS_PASS)
                        .or()
                        .eq(SmsClockInApplyDetail::getDetailAllowStatus, CLOCK_IN_APPLY_STATUS_DENY);
            });
            if(!isNullOrEmpty(search_str)){
                List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                        .lambda()
                        .like(SmsUser::getRealName, search_str))
                        .stream()
                        .map(SmsUser::getId).collect(Collectors.toList());
                mpjLambdaWrapper.and(i -> {
                    i.like(SmsClockInApply::getRepairReason, search_str);
                    if (userIds.size() > 0) {
                        i.or().in(SmsClockInApply::getApplyUserId,search_str);
                    }
                });
            }
            smsClockInApplyMpjMapper.selectJoinPage(page, SmsClockInApplyMpjResp.class,mpjLambdaWrapper);
            respList = page.getRecords()
                    .stream()
                    .map(smsExamineMPJResp -> {
                        SmsClockInApplyResp clockInApplyResp = new SmsClockInApplyResp();
                        BeanUtils.copyProperties(smsExamineMPJResp, clockInApplyResp);
                        clockInApplyResp.setApplyId(smsExamineMPJResp.getExamineId());
                        clockInApplyResp.setCreateTime(smsExamineMPJResp.getCreateTime());
                        //时间转换
                        if(!isNullOrEmpty(smsExamineMPJResp.getAbnormalDate()) && !isNullOrEmpty(smsExamineMPJResp.getRepairTime())) {
                        clockInApplyResp.setAbnormalDate(TimeUtil.DateSimpleformat(smsExamineMPJResp.getAbnormalDate()));
                            clockInApplyResp.setRepairTime(TimeUtil.TimeFormatSting(smsExamineMPJResp.getRepairTime()));
                        }
                        SmsUser applyUser = cacheUtil.getUserInfo(smsExamineMPJResp.getApplyUserId());
                        SmsClockInUserResp smsExamineUserResp = new SmsClockInUserResp();
                        if (applyUser != null) {
                            BeanUtils.copyProperties(applyUser, smsExamineUserResp);
                        }
                        clockInApplyResp.setApplyUserInfo(smsExamineUserResp);

                        SmsUser allowUser = cacheUtil.getUserInfo(smsExamineMPJResp.getDetailAllowUserId());
                        SmsClockInUserResp smsExamineAllowUserResp = new SmsClockInUserResp();
                        if (allowUser != null) {
                            BeanUtils.copyProperties(allowUser, smsExamineAllowUserResp);
                        }
                        clockInApplyResp.setAllowUserInfo(smsExamineAllowUserResp);

                        return clockInApplyResp;
                    })
                    .collect(Collectors.toList());
            total = (int) page.getTotal();
            //待办
        }else if(applyType == CLOCK_IN_EXAMINE_TYPE_ALLOW_WAIT_ME){
            List<String> roleList = cacheUtil.getRoleList(userId);//获取所有待审批申请流程节点
            List<SmsClockInApplyDetail> allDetailList =
                    clockInApplyDetailMapper.selectList(new QueryWrapper<SmsClockInApplyDetail>()
                            .lambda()
                            .eq(SmsClockInApplyDetail::getDetailAllowStatus, CLOCK_IN_APPLY_STATUS_WAIT_ALLOW));
            List<SmsClockInApplyDetail> filterDetailList = allDetailList
                    .stream()
                    .filter(detail -> {
                        if (detail.getProcessObjectType() == CLOCK_IN_OBJECT_TYPE_PERSON) {
                                    if (!detail.getProcessObjectId().equals(userId)) {
                                        return false;
                                    }
                                } else if (detail.getProcessObjectType() == CLOCK_IN_OBJECT_TYPE_ROLE) {
                                    List<String> filterRoleList = roleList.stream().filter(role -> role.equals(detail.getProcessObjectId())).collect(Collectors.toList());
                                    if (filterRoleList.size() < 1) {
                                        return false;
                                    }
                                }
                                return true;
                            }
                    ).collect(Collectors.toList());
            if(filterDetailList.size() > 0) {
                List<String> detailIDList = filterDetailList.stream().map(SmsClockInApplyDetail::getId).collect(Collectors.toList());
                Page<SmsClockInApplyMpjResp> page = new Page<>(pageNum, pageSize);
                MPJLambdaWrapper<SmsClockInApplyDetail> mpjLambdaWrapper = new MPJLambdaWrapper<>();
                mpjLambdaWrapper
                        .selectAll(SmsClockInApplyDetail.class)
                        .selectAll(SmsClockInApply.class)
                        .selectAs(SmsClockInApply::getCreateTime, "applyCreateTime")
                        .selectAs(SmsClockInApplyDetail::getId, "detailId")
                        .leftJoin(SmsClockInApply.class, SmsClockInApply::getId, SmsClockInApplyDetail::getExamineId)
                        .in(SmsMeetingRoomProcessDetail::getId, detailIDList)
                        .orderByDesc(SmsClockInApplyDetail::getDetailAllowTime)
                        .orderByDesc(SmsClockInApply::getCreateTime);
                if(!isNullOrEmpty(search_str)){
                    List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                            .lambda()
                            .like(SmsUser::getRealName, search_str))
                            .stream()
                            .map(SmsUser::getId).collect(Collectors.toList());
                    mpjLambdaWrapper.and(i -> {
                        i.like(SmsClockInApply::getRepairReason, search_str);
                        if (userIds.size() > 0) {
                            i.or().in(SmsClockInApply::getApplyUserId,search_str);
                        }
                    });
                }
                smsClockInApplyMpjMapper.selectJoinPage(page, SmsClockInApplyMpjResp.class, mpjLambdaWrapper);
                respList = page.getRecords()
                        .stream()
                        .map(smsApplyMPJResp -> {
                            SmsClockInApplyResp applyResp = new SmsClockInApplyResp();
                            BeanUtils.copyProperties(smsApplyMPJResp, applyResp);
                            applyResp.setCreateTime(smsApplyMPJResp.getCreateTime());
                            applyResp.setApplyId(smsApplyMPJResp.getExamineId());
                            //时间转换
                            if(!isNullOrEmpty(smsApplyMPJResp.getAbnormalDate()) && !isNullOrEmpty(smsApplyMPJResp.getRepairTime())) {
                                applyResp.setAbnormalDate(TimeUtil.DateSimpleformat(smsApplyMPJResp.getAbnormalDate()));
                                applyResp.setRepairTime(TimeUtil.TimeFormatSting(smsApplyMPJResp.getRepairTime()));
                            }
                            SmsUser applyUser = cacheUtil.getUserInfo(smsApplyMPJResp.getApplyUserId());
                            SmsClockInUserResp smsExamineUserResp = new SmsClockInUserResp();
                            if (applyUser != null) {
                                BeanUtils.copyProperties(applyUser, smsExamineUserResp);
                            }
                            applyResp.setApplyUserInfo(smsExamineUserResp);
                            return applyResp;
                        }).collect(Collectors.toList());
                total = (int) page.getTotal();
            }
        }
        return CommonResult.success(respList,total);
    }

    @Override
    public ResponseResult getRepairClockInApplyDetail(String applyId) {
        if(isNullOrEmpty(applyId)){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        SmsClockInApply clockInApply = clockInApplyMapper.selectById(applyId);
        if(clockInApply == null){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_APPLY_NOT_EXIST);
        }

        SmsClockInApplyResp clockInApplyResp = new SmsClockInApplyResp();
        BeanUtils.copyProperties(clockInApply,clockInApplyResp);

        clockInApplyResp.setApplyId(clockInApply.getId());
        //申请人信息
        SmsClockInUserResp clockInUserResp = new SmsClockInUserResp();
        SmsUser applyUserInfo = cacheUtil.getUserInfo(clockInApply.getApplyUserId());
        if(applyUserInfo != null){
            BeanUtils.copyProperties(applyUserInfo,clockInUserResp);
        }
        clockInApplyResp.setApplyUserInfo(clockInUserResp);
        //时间转换
        if(!isNullOrEmpty(clockInApply.getAbnormalDate()) && !isNullOrEmpty(clockInApply.getRepairTime())) {
            clockInApplyResp.setAbnormalDate(TimeUtil.DateSimpleformat(clockInApply.getAbnormalDate()));
            clockInApplyResp.setRepairTime(TimeUtil.TimeFormatSting(clockInApply.getRepairTime()));
        }
        //校验是否需要审批
        SmsClockIn smsClockIn = clockInMapper.selectById(clockInApply.getClockInId());
        if(smsClockIn == null){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_NOT_EXIST);
        }
        SmsClockInGroupSetting groupSetting = groupSettingMapper.selectById(smsClockIn.getClockInGroupId());
        if(groupSetting == null){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_GROUP_NOT_EXIST);
        }
        if(groupSetting.getIsAllow()) {
            List<SmsClockInApplyDetailResp> detailRespList = new ArrayList<>();
            detailRespList =  clockInApplyDetailMapper.selectList(new LambdaQueryWrapper<SmsClockInApplyDetail>()
                    .eq(SmsClockInApplyDetail::getExamineId, clockInApply.getId()))
                    .stream()
                    .map(detail ->{
                        SmsClockInApplyDetailResp smsClockInApplyDetailResp = new SmsClockInApplyDetailResp();
                        BeanUtils.copyProperties(detail,smsClockInApplyDetailResp);
                        //审批人信息
                        if (!isNullOrEmpty(detail.getDetailAllowUserId())) {
                            SmsClockInUserResp allowUserResp = new SmsClockInUserResp();
                            String allowUserId = detail.getDetailAllowUserId();
                            SmsUser allowUserInfo = cacheUtil.getUserInfo(allowUserId);
                            if (allowUserInfo != null) {
                                BeanUtils.copyProperties(allowUserInfo, allowUserResp);
                            }
                            smsClockInApplyDetailResp.setDetailAllowUserInfo(allowUserResp);
                        }
                        //节点信息
                        SmsClockInUserResp detailAllowUserResp = new SmsClockInUserResp();
                        BeanUtils.copyProperties(detail, smsClockInApplyDetailResp);
                        if (detail.getProcessObjectType() == CLOCK_IN_OBJECT_TYPE_PERSON) {
                            SmsUser allowUserInfo = cacheUtil.getUserInfo(detail.getProcessObjectId());
                            if (allowUserInfo != null) {
                                BeanUtils.copyProperties(allowUserInfo, detailAllowUserResp);
                            }
                            smsClockInApplyDetailResp.setDetailAllowUserInfo(detailAllowUserResp);
                        } else if (detail.getProcessObjectType() == CLOCK_IN_OBJECT_TYPE_ROLE) {
                            SmsRole smsRole = smsRoleMapper.selectById(detail.getProcessObjectId());
                            if (smsRole != null) {
                                smsClockInApplyDetailResp.setObjectName(smsRole.getRoleName());
                            }
                        }
                        return smsClockInApplyDetailResp;
                    })
                    .collect(Collectors.toList());

            clockInApplyResp.setDetailRespList(detailRespList);
        }
        return CommonResult.success(clockInApplyResp);
    }

    @Override
    @Transactional
    public ResponseResult allowRepairClockInApply(String userId, SmsClockInApplyAllowReq allowReq) {
        if(isNullOrEmpty(allowReq.getDetailId()) || isNullOrEmpty(allowReq.getApplyId()) || isNullOrEmpty(allowReq.getDetailAllowStatus())){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        //校验审批状态
        if(allowReq.getDetailAllowStatus() != CLOCK_IN_APPLY_STATUS_PASS && allowReq.getDetailAllowStatus() != CLOCK_IN_APPLY_STATUS_DENY){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }


        SmsClockInApply clockInApply = clockInApplyMapper.selectById(allowReq.getApplyId());
        if(clockInApply == null){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_APPLY_NOT_EXIST);
        }
        SmsClockInApplyDetail clockInApplyDetail = clockInApplyDetailMapper.selectById(allowReq.getDetailId());
        if(clockInApplyDetail == null){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_ALLOW_DETAIL_NOT_EXIST);
        }
        //校验节点是否是待办状态
        if(clockInApplyDetail.getDetailAllowStatus() != CLOCK_IN_APPLY_STATUS_WAIT_ALLOW){
            return CommonResult.failed(CommonCodeEnum.CLOCK_IN_ALLOW_FAIL);
        }
        //校验是否是本人审批
        if (clockInApplyDetail.getProcessObjectType() == CLOCK_IN_OBJECT_TYPE_PERSON) {
            if (!clockInApplyDetail.getProcessObjectId().equals(userId)) {
                return CommonResult.failed(CommonCodeEnum.CLOCK_IN_ALLOW_FAIL);
            }
        } else if (clockInApplyDetail.getProcessObjectType() == CLOCK_IN_OBJECT_TYPE_ROLE) {
            List<String> roleList = cacheUtil.getRoleList(userId);
            if (!roleList.contains(clockInApplyDetail.getProcessObjectId())) {
                return CommonResult.failed(CommonCodeEnum.CLOCK_IN_ALLOW_FAIL);
            }
        }


        //修改节点状态
        SmsClockInApplyDetail updateDetail = new SmsClockInApplyDetail();
        updateDetail.setDetailAllowStatus(allowReq.getDetailAllowStatus());
        updateDetail.setDetailAllowOpinion(allowReq.getDetailAllowOpinion());
        updateDetail.setDetailAllowUserId(userId);
        updateDetail.setDetailAllowTime(new Date());
        clockInApplyDetailMapper.update(updateDetail,new LambdaQueryWrapper<SmsClockInApplyDetail>()
        .eq(SmsClockInApplyDetail::getExamineId,allowReq.getApplyId()));
        //修改申请表
        SmsClockInApply updateClockInApply = new SmsClockInApply();
        updateClockInApply.setId(allowReq.getApplyId());
        updateClockInApply.setProcessEndTime(new Date());
        updateClockInApply.setAllowStatus(allowReq.getDetailAllowStatus());
        clockInApplyMapper.updateById(updateClockInApply);
        //修改打卡表
        if(allowReq.getDetailAllowStatus() == CLOCK_IN_APPLY_STATUS_PASS) {
            SmsClockIn updateClockIn = new SmsClockIn();
            updateClockIn.setId(clockInApply.getClockInId());
            if (!isNullOrEmpty(allowReq.getAbnormalDate()) && !isNullOrEmpty(allowReq.getRepairTime())) {
                updateClockIn.setClockInDate(TimeUtil.StringtoDate(allowReq.getAbnormalDate()));//补卡日期
                updateClockIn.setClockInTime(TimeUtil.TimeFormat(allowReq.getRepairTime()));//补卡时间
            }
            updateClockIn.setClockInState(CLOCK_IN_STATE_NORMAL);//打卡状态 正常
            clockInMapper.updateById(updateClockIn);
        }
        //消息通知
        boolean result_status = false;
        if (allowReq.getDetailAllowStatus() == CLOCK_IN_APPLY_STATUS_PASS) {
            result_status = true;
        }
        newTipsUtil.allowFinishTips(allowReq.getApplyId(), userId, result_status);

        return CommonResult.success();
    }

    @Override
    public ResponseResult getAllRepairClockInApply(Integer allowStatus,String applyName,Integer pageSize, Integer pageNum,String abnormalDate) {
        Page<SmsClockInApply> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<SmsClockInApply> queryWrapper = new LambdaQueryWrapper<>();
        if(!isNullOrEmpty(allowStatus)){
            queryWrapper.eq(SmsClockInApply::getAllowStatus,allowStatus);
        }
        if (!isNullOrEmpty(applyName)) {
            List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                    .lambda()
                    .like(SmsUser::getRealName, applyName))
                    .stream()
                    .map(SmsUser::getId).collect(Collectors.toList());
            if(userIds.size() > 0) {
                queryWrapper.in(SmsClockInApply::getApplyUserId, userIds);
            }
        }
        if(!isNullOrEmpty(abnormalDate)){
            queryWrapper.eq(SmsClockInApply::getAbnormalDate,abnormalDate);
        }
        queryWrapper.orderByDesc(SmsClockInApply::getCreateTime);
        clockInApplyMapper.selectPage(page,queryWrapper);
        List<SmsClockInApplyResp> clockInApplyList = new ArrayList<>();
        if(page.getRecords() != null) {
            clockInApplyList = page.getRecords()
                    .stream()
                    .map(clockInApply -> {
                        SmsClockInApplyResp smsClockInApplyResp = new SmsClockInApplyResp();
                        BeanUtils.copyProperties(clockInApply, smsClockInApplyResp);
                        smsClockInApplyResp.setApplyId(clockInApply.getId());
                        //时间转换
                        smsClockInApplyResp.setAbnormalDate(TimeUtil.DateSimpleformat(clockInApply.getAbnormalDate()));
                        smsClockInApplyResp.setRepairTime(TimeUtil.TimeFormatSting(clockInApply.getRepairTime()));
                        //申请人
                        SmsUser userInfo = cacheUtil.getUserInfo(clockInApply.getApplyUserId());
                        SmsClockInUserResp smsClockInUserResp = new SmsClockInUserResp();
                        if (userInfo != null) {
                            BeanUtils.copyProperties(userInfo, smsClockInUserResp);
                        }
                        smsClockInApplyResp.setApplyUserInfo(smsClockInUserResp);
                        return smsClockInApplyResp;
                    })
                    .collect(Collectors.toList());
        }
        int total = (int)page.getTotal();
        return CommonResult.success(clockInApplyList,total);
    }

    @Override
    @Async
    public Future<ResponseResult> exportApplyHistory(SmsClockInApplyHistoryReq req, HttpServletResponse response) {
        try {
            LambdaQueryWrapper<SmsClockInApply> queryWrapper = new LambdaQueryWrapper<>();

            if(!isNullOrEmpty(req.getApplyName())){
                List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                        .lambda()
                        .like(SmsUser::getRealName, req.getApplyName()))
                        .stream()
                        .map(SmsUser::getId).collect(Collectors.toList());
                if(userIds.size() > 0) {
                    queryWrapper.in(SmsClockInApply::getApplyUserId, userIds);
                }
            }
            if(!isNullOrEmpty(req.getAbnormalDate())){
                queryWrapper.eq(SmsClockInApply::getAbnormalDate,req.getAbnormalDate());
            }
            if(!isNullOrEmpty(req.getAllowStatus())){
                queryWrapper.eq(SmsClockInApply::getAllowStatus,req.getAllowStatus());
            }
            queryWrapper.orderByDesc(SmsClockInApply::getCreateTime);
            List<SmsClockInApply> list = clockInApplyMapper.selectList(queryWrapper);
            //表头数据
            String[] header = req.getLimitColumn().toArray(new String[0]);
            double sheetNum;
            //声明一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            if (list != null && list.size() > 0) {
                sheetNum = Math.ceil((double) list.size() / PER_SHEET_NUM);
                for (int k = 0; k < sheetNum; k++) {
                    //生成一个表格，设置表格名称为"资源导出表"
                    HSSFSheet sheet = workbook.createSheet("考勤记录导出表" + (k + 1));

                    //设置表格列宽度为10个字节
                    sheet.setDefaultColumnWidth(12);
                    //创建标题的显示样式
                    HSSFCellStyle headerStyle = workbook.createCellStyle();
                    headerStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
                    headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

                    HSSFFont f = workbook.createFont();
                    f.setFontHeightInPoints((short) 10);//字号
                    f.setBold(true);//加粗
                    headerStyle.setFont(f);
                    //创建第一行表头
                    HSSFRow headrow = sheet.createRow(0);

                    //遍历添加表头(下面模拟遍历学生，也是同样的操作过程)
                    for (int i = 0; i < header.length + 1; i++) {
                        //创建一个单元格
                        HSSFCell cell = headrow.createCell(i);

                        if (i == 0) {
                            //创建一个内容对象
                            HSSFRichTextString text = new HSSFRichTextString("序号");
                            //将内容对象的文字内容写入到单元格中
                            cell.setCellValue(text);
                            cell.setCellStyle(headerStyle);
                            continue;
                        }
                        //创建一个内容对象
                        String header1 = apiModelUtil.getFieldValueByFieldName(SmsClockInApply.class, header[i - 1]);
                        HSSFRichTextString text = new HSSFRichTextString(header1);

                        //将内容对象的文字内容写入到单元格中
                        cell.setCellValue(text);
                        cell.setCellStyle(headerStyle);
                    }

                   //判断是否需要添加流程表头
                    if (req.getIsExportProcess() == EXPORT_PROCESS_TRUE) {
                        Integer origin_num = header.length + 1;
                        addProcessTableHead(headrow, headerStyle, origin_num, "补卡");
                    }

                    int range = PER_SHEET_NUM;
                    if (k + 1 == sheetNum) {
                        range = list.size() - (PER_SHEET_NUM) * k;
                    }
                    for (int i = 0; i < range; i++) {
                        //创建一行
                        HSSFRow row1 = sheet.createRow(i + 1);
                        SmsClockInApply smsClockInApply = list.get((PER_SHEET_NUM) * k + i);
                        Map map = JSONObject.parseObject(JSON.toJSONString(smsClockInApply), Map.class);
                        row1.createCell(0).setCellValue(new HSSFRichTextString(i + 1 + ""));
                        for (int j = 0; j < header.length; j++) {
                            String rowContent = "";
                          if(map.get(header[j]) instanceof Long){
                                rowContent = TimeUtil.DateHanZiSimpleTimestamp((long) map.get(header[j]));
                            }else if(header[j].equals("allowStatus")) {
                              if ((int) map.get(header[j]) == CLOCK_IN_APPLY_STATUS_WAIT_ALLOW) {
                                  rowContent = "待审批";
                              } else if ((int) map.get(header[j]) == CLOCK_IN_APPLY_STATUS_PASS) {
                                  rowContent = "通过";
                              } else {
                                  rowContent = "驳回";
                              }
                          } else if(header[j].equals("repairTime")) {
                              if (map.get(header[j]) != null && map.get(header[j]) instanceof Integer) {
                                  rowContent = TimeUtil.TimeHanZiFormatSting(Long.parseLong(map.get(header[j]).toString()));
                              } else {
                                  rowContent = "";
                              }
                          }else if(header[j].equals("applyUserId")){
                                    SmsUser smsUser = cacheUtil.getUserInfo(smsClockInApply.getApplyUserId());
                                    if (smsUser!=null){
                                        rowContent = smsUser.getRealName();
                                    }else{
                                        rowContent = "";
                                    }
                                }else{
                                    rowContent = String.valueOf(map.get(header[j]));
                                }
                            row1.createCell(j + 1).setCellValue(new HSSFRichTextString(rowContent));
                        }

                        if (req.getIsExportProcess() == EXPORT_PROCESS_TRUE) {
                                Integer origin_num = header.length + 1;
                                    List<SmsClockInApplyDetail> detailList =
                                            clockInApplyDetailMapper.selectList(new QueryWrapper<SmsClockInApplyDetail>()
                                                    .lambda()
                                                    .eq(SmsClockInApplyDetail::getExamineId, smsClockInApply.getId()));
                                    if(detailList != null && detailList.size() > 0){
                                        for (SmsClockInApplyDetail detail : detailList) {
                                            if(detail.getDetailAllowUserId() != null){
                                                if (detail.getId() == null) {
                                                    origin_num += 4;
                                                } else {
                                                    //审批人
                                                    SmsUser user = cacheUtil.getUserInfo(detail.getDetailAllowUserId());
                                                    if (user == null) {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString(""));
                                                    } else {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString(user.getRealName()));
                                                    }

                                                    //审批时间
                                                    Date allow_time = detail.getDetailAllowTime();
                                                    if (allow_time == null) {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString(""));
                                                    } else {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString(TimeUtil.DateHanZiSimpleFormat(allow_time)));
                                                    }

                                                    //审批状态
                                                    Integer allow_status = detail.getDetailAllowStatus();
                                                    if (allow_status == CLOCK_IN_APPLY_STATUS_PASS) {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString("同意"));
                                                    } else if (allow_status == CLOCK_IN_APPLY_STATUS_DENY) {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString("驳回"));
                                                    } else {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString(""));
                                                    }

                                                    //审批意见
                                                    String allow_option = detail.getDetailAllowOpinion();
                                                    if (isNullOrEmpty(allow_option)) {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString(""));
                                                    } else {
                                                        row1.createCell(origin_num++).setCellValue(new HSSFRichTextString(allow_option));
                                                    }
                                                }
                                            }
                                        }
                                    }

                        }
                    }
                }
            }

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("考勤申请记录导出表.xlsx", "utf-8"));
            response.setCharacterEncoding("utf-8");
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("考勤申请记录导出表.xlsx", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
            //刷新缓冲
            response.flushBuffer();
            //workbook将Excel写入到response的输出流中，供页面下载
            OutputStream os = response.getOutputStream();
            workbook.write(os);

            workbook.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return null;
    }

    @Override
    public ResponseResult getAllRepairClockIn(String clockName, Integer pageSize, Integer pageNum, String clockInDate, Integer clockInType, Integer clockInState) {
        Page<SmsClockIn> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<SmsClockIn> queryWrapper = new LambdaQueryWrapper<>();
        if(!isNullOrEmpty(clockName)){
            List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                    .lambda()
                    .like(SmsUser::getRealName, clockName))
                    .stream()
                    .map(SmsUser::getId).collect(Collectors.toList());
            if(userIds.size() > 0) {
                queryWrapper.in(SmsClockIn::getUserId, userIds);
            }
        }
        if(!isNullOrEmpty(clockInDate)){
            queryWrapper.eq(SmsClockIn::getClockInDate,clockInDate);
        }
        if(!isNullOrEmpty(clockInType)){
            queryWrapper.eq(SmsClockIn::getClockInType,clockInType);
        }
        if(!isNullOrEmpty(clockInState)){
            queryWrapper.eq(SmsClockIn::getClockInState,clockInState);
        }
        queryWrapper.orderByDesc(SmsClockIn::getCreateTime);
        clockInMapper.selectPage(page,queryWrapper);
        List<SmsClockInListResp> clockInInfoListResp = new ArrayList<>();
        if(page.getRecords() != null){
            clockInInfoListResp = page.getRecords()
                    .stream()
                    .map(clockInInfo ->{
                        SmsClockInListResp smsClockInInfoResp = new SmsClockInListResp();
                        BeanUtils.copyProperties(clockInInfo,smsClockInInfoResp);
                        if (!isNullOrEmpty(clockInInfo.getClockInTime())) {
                            smsClockInInfoResp.setClockInTime(TimeUtil.TimeAndSecFormat(clockInInfo.getClockInTime()));
                        }
                        if (!isNullOrEmpty(clockInInfo.getClockInDate())) {
                            smsClockInInfoResp.setClockInDate(TimeUtil.DateFormatSting(clockInInfo.getClockInDate()));
                        }
                        smsClockInInfoResp.setClockInType(clockInInfo.getClockInType());
                        smsClockInInfoResp.setClockInState(clockInInfo.getClockInState());
                        SmsClockInUserResp smsClockInUserResp = new SmsClockInUserResp();
                        SmsUser userInfo = cacheUtil.getUserInfo(clockInInfo.getUserId());
                        if(userInfo != null){
                            BeanUtils.copyProperties(userInfo,smsClockInUserResp);
                            smsClockInInfoResp.setClockInUserInfo(smsClockInUserResp);
                        }
                        return smsClockInInfoResp;
                    })
                    .collect(Collectors.toList());
        }
        int total = (int)page.getTotal();
        return CommonResult.success(clockInInfoListResp,total);
    }

    @Override
    @Async
    public Future<ResponseResult> exportExamineHistoryList(SmsClockInHistoryReq req, HttpServletResponse response) {
        try {
            LambdaQueryWrapper<SmsClockIn> queryWrapper = new LambdaQueryWrapper<>();

            if(!isNullOrEmpty(req.getClockInName())){
                List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                        .lambda()
                        .like(SmsUser::getRealName, req.getClockInName()))
                        .stream()
                        .map(SmsUser::getId).collect(Collectors.toList());
                if(userIds.size() > 0) {
                    queryWrapper.in(SmsClockIn::getUserId, userIds);
                }
            }
            if(!isNullOrEmpty(req.getClockInDate())){
                queryWrapper.eq(SmsClockIn::getClockInDate,req.getClockInDate());
            }
            if(!isNullOrEmpty(req.getClockInType())){
                queryWrapper.eq(SmsClockIn::getClockInType,req.getClockInType());
            }
            if(!isNullOrEmpty(req.getClockInState())){
                queryWrapper.eq(SmsClockIn::getClockInState,req.getClockInState());
            }
            queryWrapper.orderByDesc(SmsClockIn::getCreateTime);
            List<SmsClockIn> list = clockInMapper.selectList(queryWrapper);
            //表头数据
            String[] header = req.getLimitColumn().toArray(new String[0]);
            double sheetNum;
            //声明一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            if (list != null && list.size() > 0) {
                sheetNum = Math.ceil((double) list.size() / PER_SHEET_NUM);
                for (int k = 0; k < sheetNum; k++) {
                    //生成一个表格，设置表格名称为"资源导出表"
                    HSSFSheet sheet = workbook.createSheet("考勤记录导出表" + (k + 1));

                    //设置表格列宽度为10个字节
                    sheet.setDefaultColumnWidth(12);
                    //创建标题的显示样式
                    HSSFCellStyle headerStyle = workbook.createCellStyle();
                    headerStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
                    headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

                    HSSFFont f = workbook.createFont();
                    f.setFontHeightInPoints((short) 10);//字号
                    f.setBold(true);//加粗
                    headerStyle.setFont(f);
                    //创建第一行表头
                    HSSFRow headrow = sheet.createRow(0);

                    //遍历添加表头(下面模拟遍历学生，也是同样的操作过程)
                    for (int i = 0; i < header.length + 1; i++) {
                        //创建一个单元格
                        HSSFCell cell = headrow.createCell(i);

                        if (i == 0) {
                            //创建一个内容对象
                            HSSFRichTextString text = new HSSFRichTextString("序号");
                            //将内容对象的文字内容写入到单元格中
                            cell.setCellValue(text);
                            cell.setCellStyle(headerStyle);
                            continue;
                        }
                        //创建一个内容对象
                        String header1 = apiModelUtil.getFieldValueByFieldName(SmsClockIn.class, header[i - 1]);
                        HSSFRichTextString text = new HSSFRichTextString(header1);

                        //将内容对象的文字内容写入到单元格中
                        cell.setCellValue(text);
                        cell.setCellStyle(headerStyle);
                    }

                    int range = PER_SHEET_NUM;
                    if (k + 1 == sheetNum) {
                        range = list.size() - (PER_SHEET_NUM) * k;
                    }
                    for (int i = 0; i < range; i++) {
                        //创建一行
                        HSSFRow row1 = sheet.createRow(i + 1);
                        SmsClockIn smsClockIn = list.get((PER_SHEET_NUM) * k + i);
                        Map map = JSONObject.parseObject(JSON.toJSONString(smsClockIn), Map.class);
                        row1.createCell(0).setCellValue(new HSSFRichTextString(i + 1 + ""));
                        for (int j = 0; j < header.length; j++) {
                            String rowContent = "";
                            if (header[j].equals("clockInDate")) {
                                rowContent = TimeUtil.DateHanZiSimpleTimestamp((long) map.get(header[j]));
                            }else if(header[j].equals("clockInTime")) {
                                if( map.get(header[j]) != null && map.get(header[j]) instanceof Integer) {
                                    rowContent = TimeUtil.TimeHanZiFormatSting(Long.parseLong(map.get(header[j]).toString()));
                                }else {
                                    rowContent = "";
                                }
                            }else if(map.get(header[j]) instanceof Long){
                                rowContent = TimeUtil.DateHanZiSimpleTimestamp((long) map.get(header[j]));
                            }else if(header[j].equals("clockInState")){
                                if((int)map.get(header[j]) == CLOCK_IN_STATE_NORMAL){
                                    rowContent = "正常";
                                }else if((int)map.get(header[j]) == CLOCK_IN_STATE_LACK){
                                    rowContent = "缺卡";
                                }else if((int)map.get(header[j]) == CLOCK_IN_STATE_LATE){
                                    rowContent = "迟到";
                                }else {
                                    rowContent = "早退";
                                }
                            } else if(header[j].equals("clockInType")){
                                if((int)map.get(header[j]) == CLOCK_IN_TYPE_START){
                                    rowContent = "上班";
                                }else {
                                    rowContent = "下班";
                                }
                            }else if(header[j].equals("remark")){
                                if(map.get(header[j]) == null){
                                    rowContent = "";
                                }
                            }else {
                                if (header[j].equals("userId")){
                                    SmsUser smsUser = cacheUtil.getUserInfo(smsClockIn.getUserId());
                                    if (smsUser!=null){
                                        rowContent = smsUser.getRealName();
                                    }else{
                                        rowContent = "";
                                    }
                                }else{
                                    rowContent = String.valueOf(map.get(header[j]));
                                }
                            }
                            row1.createCell(j + 1).setCellValue(new HSSFRichTextString(rowContent));
                        }

                    }
                }
            }

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("考勤记录导出表.xlsx", "utf-8"));
            response.setCharacterEncoding("utf-8");
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("考勤记录导出表.xlsx", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
            //刷新缓冲
            response.flushBuffer();
            //workbook将Excel写入到response的输出流中，供页面下载
            OutputStream os = response.getOutputStream();
            workbook.write(os);

            workbook.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return null;
    }
    private void addProcessTableHead(HSSFRow headRow, HSSFCellStyle headerStyle, Integer origin_cell_num, String originHeadContent) {
        Integer cell_num = origin_cell_num;

        setTableHead(headRow, headerStyle, cell_num++, originHeadContent + "审批人");
        setTableHead(headRow, headerStyle, cell_num++, originHeadContent + "审批时间");
        setTableHead(headRow, headerStyle, cell_num++, originHeadContent + "审批状态");
        setTableHead(headRow, headerStyle, cell_num, originHeadContent + "审批意见");

    }

    private void setTableHead(HSSFRow headRow, HSSFCellStyle headerStyle, Integer cell_num, String headContent) {
        HSSFCell cell = headRow.createCell(cell_num);
        //创建一个内容对象
        HSSFRichTextString text = new HSSFRichTextString(headContent);

        //将内容对象的文字内容写入到单元格中
        cell.setCellValue(text);
        cell.setCellStyle(headerStyle);
    }
}
